package com.richard.library.http.download;

import androidx.annotation.NonNull;

import com.richard.library.http.dict.ResponseCode;
import com.richard.library.http.exception.HttpException;
import com.richard.library.http.https.CertificateIgnoreSSLParams;
import com.richard.library.http.https.SSLParams;
import com.richard.library.http.request.BasicAPIService;
import com.richard.library.http.request.HttpError;
import com.richard.library.http.util.Utils;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.X509TrustManager;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Retrofit;


/**
 * <pre>
 * Description : 文件下载工具
 * Author : admin-richard
 * Date : 2019-11-22 14:38
 * Changelog:
 * Version            Date            Author              Detail
 * ----------------------------------------------------------------------
 * 1.0         2019-11-22 14:38     admin-richard         new file.
 * </pre>
 */
public final class FileDownloader {

    //请求超时时间设置，单位：毫秒
    public static long CONNECT_TIMEOUT = 15000;
    public static long READ_TIMEOUT = 15000;
    public static long WRITE_TIMEOUT = 15000;

    private volatile BasicAPIService basicApiService;
    private Call<ResponseBody> call;
    private FileDownloadRetrofitCallback callback;

    /**
     * 异步下载文件
     *
     * @param downloadURL 下载链接URL
     * @param callback    下载回调
     */
    public synchronized void download(String downloadURL, FileDownloadRetrofitCallback callback) {
        this.cancelDownload();
        this.callback = callback;
        call = this.getAPIService().doGetStreaming(
                downloadURL
                , new HashMap<>()
                , new HashMap<>()
        );
        call.enqueue(callback);
    }

    /**
     * 同步下载文件
     *
     * @param downloadURL 下载地址
     * @param saveFile    文件保存地址
     * @return 下载成功文件
     * @throws IOException e
     */
    public synchronized File download(String downloadURL, File saveFile) throws IOException {
        this.cancelDownload();
        call = this.getAPIService().doGetStreaming(
                downloadURL
                , new HashMap<>()
                , new HashMap<>()
        );

        retrofit2.Response<ResponseBody> response = call.execute();
        if (response.code() != 200) {
            throw new HttpException(HttpError.convertErrorMessage(response.code()));
        }

        if (response.body() == null) {
            throw new HttpException(ResponseCode.BODY_NULL.getMessage());
        }

        //保存文件
        return Utils.saveFile(response.body().byteStream(), saveFile);
    }

    /**
     * 取消下载
     */
    public void cancelDownload() {
        if (call != null && !call.isCanceled()) {
            call.cancel();
        }
        call = null;
        callback = null;
    }


    /**
     * 获取retrofit
     */
    private BasicAPIService getAPIService() {
        if (basicApiService == null) {
            synchronized (FileDownloader.class) {
                if (basicApiService == null) {
                    Retrofit retrofit = new Retrofit.Builder()
                            .client(getOkHttpClient())
                            .baseUrl("http://www/")
                            .build();
                    basicApiService = retrofit.create(BasicAPIService.class);
                }
            }
        }

        return basicApiService;
    }

    /**
     * 初始化OkHttpClient
     */
    private OkHttpClient getOkHttpClient() {
        //默认忽略https的证书
        SSLParams httpSSLParams = CertificateIgnoreSSLParams.getSSLParams();

        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)//是否开启重连机制
                .sslSocketFactory(
                        httpSSLParams.getsSLSocketFactory()
                        , (X509TrustManager) httpSSLParams.getTrustManager()
                )
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)//设置超时时间
                .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)//设置读取超时时间
                .writeTimeout(WRITE_TIMEOUT, TimeUnit.MILLISECONDS);//设置写的超时时间

        if (callback != null) {
            builder.networkInterceptors().add(new Interceptor() {
                @NonNull
                @Override
                public Response intercept(@NonNull Chain chain) throws IOException {
                    Response originalResponse = chain.proceed(chain.request());
                    return originalResponse
                            .newBuilder()
                            .body(new FileResponseBody(originalResponse.body(), callback))
                            .build();
                }
            });
        }

        return builder.build();
    }

}
